package de.breitbeil.jbooking.ui.dataview;

import java.lang.reflect.Constructor;

import org.springframework.richclient.application.event.LifecycleApplicationEvent;
import org.springframework.richclient.dialog.CloseAction;
import org.springframework.richclient.dialog.ConfirmationDialog;
import org.springframework.richclient.dialog.FormBackedDialogPage;
import org.springframework.richclient.dialog.TitledPageApplicationDialog;
import org.springframework.richclient.form.Form;
import org.springframework.util.Assert;

import de.breitbeil.jbooking.dao.GenericDao;

/**
 * This dialog is responsible to edit and create objects maintained 
 * by a {@link DataView}.
 * <p>
 * There is no need to use this class directly. It will be initialized
 * by the {@link DataView}.
 * 
 * @author Dominik Breitbeil
 *
 */
public class DataViewPropertiesDialog extends TitledPageApplicationDialog {

    /** The form that allows for editing the object. */
    private Form form;

    /** Are we creating a new object or editing an existing one? */
    private boolean creatingNew = false;

    /** The data store holding all our objects, used to add a new contact. */
    private GenericDao dao;
    
    private String id;

    /**
     * Creates a dialog for creating a new object.
     * 
     * @param id form id.
     * @param dao datastore the created object will be stored in.
     * @param entity entitiy of the form.
     * @param formClass the underlying form for the dialog.
     */
    public DataViewPropertiesDialog(String id, GenericDao dao, Class entity, Class<? extends Form> formClass) {
        this(id, null, dao, entity, formClass);
    }

    /**
     * Create a dialog for editing or creating an object. If the given object is
     * <code>null</code> it will create a new object in the datastore.
     * 
     * @param id form id
     * @param object object to edit. If <code>null</code> the dialog creates a new object on its 
     * own and saves it in the datastore.
     * @param dao the datastore
     * @param entity type of the object.
     * @param formClass the underlaying form for the dialog.
     */
    public DataViewPropertiesDialog(String id, Object object, GenericDao dao, Class entity, Class<? extends Form> formClass) {
        Assert.notNull(dao, "The dao is required to edit an object");
        if (object == null) {
            creatingNew = true;
            try {
                object = entity.newInstance();
            } catch (Exception e) {
                throw new IllegalArgumentException("Given entity cannot be instantiate.");
            } 
        }
        setCloseAction(CloseAction.DISPOSE);
        form = createFormInstance(object, entity, formClass);
        setDialogPage(new FormBackedDialogPage(form));
        this.dao = dao;
        this.id = id;
    }

    /**
     * Sets the title of the dialog. 
     * @see org.springframework.richclient.dialog.ApplicationDialog#onAboutToShow()
     */
    protected void onAboutToShow() {
        if (creatingNew) {
        	setTitle( getMessage(id+".new.title") );
        }
        else {
        	setTitle( getMessage(id+".edit.title") );  
        }
    }

    /**
     * Saves the edited object and notifies the application about the new
     * created or edited object.
     * 
     * @see org.springframework.richclient.dialog.ApplicationDialog#onFinish()
     */
    protected boolean onFinish() {
        // commit any buffered edits to the model
        form.getFormModel().commit();
        Object formObject = form.getFormObject();
        
        // Update the persistent store with the new/modified object.
        dao.makePersistent(formObject);
        
        // And notify the rest of the application of the change
        String eventType = (creatingNew)? LifecycleApplicationEvent.CREATED :  LifecycleApplicationEvent.MODIFIED;
        getApplicationContext().publishEvent(new LifecycleApplicationEvent(eventType, formObject));
        
        return true;
    }

    /**
     * If there are any changes to the formobject, the user will be asked if he 
     * wants to loose them.
     * 
     * @see org.springframework.richclient.dialog.ApplicationDialog#onCancel()
     */
    protected void onCancel() {
        // Warn the user if they are about to discard their changes
        if (form.getFormModel().isDirty()) {
            String msg = getMessage(id+".dirtyCancelMessage");
            String title = getMessage(id+".dirtyCancelTitle");
            ConfirmationDialog dlg = new ConfirmationDialog(title, msg) {
                protected void onConfirm() {
                    DataViewPropertiesDialog.super.onCancel();
                }
            };
            dlg.showDialog();
        }
        else {
            super.onCancel();
        }
    }
    
    
    /**
     * Creates a new form instance for the provided object.
     * 
     * @param object the formobject.
     * @param entity type of the formobject.
     * @param form type of the form. The form needs a constructor with one argument, the formobject.
     * @return
     */
    private Form createFormInstance(Object object, Class entity, Class<? extends Form> form) {
        try {
            Constructor<? extends Form> con = form.getConstructor(entity);
            return con.newInstance(object);
        } catch (Exception e) {
            throw new IllegalArgumentException("Form class must have a constructor with one entity argument.", e);
        }
    }

}
